package com.demo.gateway.config;

import com.demo.gateway.utils.JwtTokenProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
import org.springframework.security.web.server.authentication.ServerAuthenticationConverter;
import reactor.core.publisher.Mono;

import java.util.*;

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {

    @Value("${jwt.header}")
    private String jwtHeader;

    @Value("${jwt.prefix}")
    private String jwtPrefix;


    private static List<String> ignorePaths = new ArrayList<>(Arrays.asList("/auth/login","/auth/logout","/actuator/health"));

    private final JwtTokenProvider jwtTokenProvider;

    public SecurityConfig(JwtTokenProvider jwtTokenProvider) {
        this.jwtTokenProvider = jwtTokenProvider;
    }

    /**
     * 安全过滤器链配置
     */
    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
        return http
                .csrf().disable()  // 网关层禁用 CSRF
                .authorizeExchange()
                // 白名单路径允许匿名访问
                .pathMatchers(ignorePaths.toArray(new String[0])).permitAll()
                // 其他所有路径需要认证
                .anyExchange().authenticated()
                .and()
                // 添加 JWT 认证过滤器（在默认认证过滤器之前执行）
                .addFilterAt(authenticationWebFilter(), SecurityWebFiltersOrder.AUTHENTICATION)
                .build();
    }

    /**
     * 自定义 JWT 认证过滤器
     */
    private AuthenticationWebFilter authenticationWebFilter() {
        AuthenticationWebFilter filter = new AuthenticationWebFilter(authenticationManager());
        // 设置 Token 转换器（从请求头提取并转换为认证信息）
        filter.setServerAuthenticationConverter(jwtAuthenticationConverter());
        return filter;
    }

    /**
     * 认证管理器（用于验证 Token 中的用户信息）
     */
    @Bean
    public ReactiveAuthenticationManager authenticationManager() {
        // 模拟用户详情服务（实际项目需从数据库查询）
        UserDetails user = User.withUsername("user")
                .password(passwordEncoder().encode("123456"))
                .roles("USER")
                .build();
        MapReactiveUserDetailsService userDetailsService = new MapReactiveUserDetailsService(user);

        return new UserDetailsRepositoryReactiveAuthenticationManager(userDetailsService);
    }

    /**
     * JWT 认证转换器：从请求头提取 Token 并转换为认证信息
     */
    private ServerAuthenticationConverter jwtAuthenticationConverter() {
        return exchange -> {
            // 1. 从请求头获取 Token
            String token = exchange.getRequest().getHeaders().getFirst(jwtHeader);

            // 2. 验证 Token 格式（是否以指定前缀开头）
            if (token == null || !token.startsWith(jwtPrefix + " ")) {
                return Mono.empty();  // 无有效 Token，返回空（后续会触发未认证）
            }

            // 3. 移除前缀，获取纯 Token
            String tokenValue = token.substring(jwtPrefix.length() + 1);

            // 4. 验证 Token 有效性
            if (!jwtTokenProvider.validateToken(tokenValue)) {
                return Mono.empty();  // Token 无效，返回空
            }

            // 5. 从 Token 中获取用户名，构建认证信息（这里简化处理，实际可解析角色等信息）
            String username = jwtTokenProvider.getUsername(tokenValue);
            String password = jwtTokenProvider.getPassword(tokenValue);

            // 构建未认证的 UsernamePasswordAuthenticationToken（后续由认证管理器验证）
            return Mono.just(new UsernamePasswordAuthenticationToken(username, password, Arrays.asList()));
        };
    }

    /**
     * 密码编码器（用于加密和解密密码）
     */
//    @Bean
//    public PasswordEncoder passwordEncoder() {
//        return new BCryptPasswordEncoder();
//    }
    @Bean
    public PasswordEncoder passwordEncoder() {
        // 定义加密算法映射（key 是算法 ID，value 是对应的编码器）
        Map<String, PasswordEncoder> encoders = new HashMap<>();
        encoders.put("bcrypt", new BCryptPasswordEncoder());
        encoders.put("noop", NoOpPasswordEncoder.getInstance()); // 不加密（仅测试用）

        // 创建 DelegatingPasswordEncoder，指定默认算法为 bcrypt
        return new DelegatingPasswordEncoder("bcrypt", encoders);
    }
}